{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Termites\n", "\n", "Consider a simple termite that only follows these simple rules:\n", "\n", "1. If you see a wood chip, and you are not carrying one, pick it up\n", "2. If you see a wood chip, and you are carrying one, then drop it\n", "3. Otherwise, move in your default direction \n", "4. Every once in awhile, change direction\n", "\n", "Now, imagine a few of these termites roaming around a flat world, scattered with wood chips. What would happen? How can we model this world?\n", "\n", "## Simulation\n", "\n", "First, we must identify the objects we wish to model. Possibilities include: \n", "\n", "* termites\n", "* world\n", "* wood chips\n", "\n", "First, let's consider what properties a termite should have:\n", "\n", "* position in the world\n", "* whether it is carrying a wood chip or not\n", "* direction heading (vector, velocity on x and y)\n", "\n", "Also, what actions must a termite be able to do:\n", "\n", "* move in the world\n", "* pick up a wood chip\n", "* drop a wood chip\n", "* draw itself\n", "\n", "We might want to add other methods, but it needs to at least support those.\n", "\n", "## Termite\n", "\n", "So, let's put together a termite class. It might look something like:\n", "\n", "```java\n", "class Termite {\n", " int x;\n", " int y;\n", " int vx;\n", " int vy;\n", " int carrying;\n", " \n", " Termite(int x, int y) { //constructor\n", " this.x = int(x);\n", " this.y = int(y);\n", " this.randomizeDirection();\n", " this.carrying = 0;\n", " }\n", "\n", " ...\n", "}\n", "```\n", "\n", "In thinking about the world, and wood chips, it might be that representing them as an object might be overkill. For example, if we imagine the world as a 2D matrix, then we could represent the presence of food with a 1, and the absence of food with a 0. Likewise, carrying can just be a 1 (for yes), and 0 (for no).\n", "\n", "It may be that instead of having termites bounce off of the walls (like a ball simulation) that we instead have them \"wrap\" around (like a [torus](https://en.wikipedia.org/wiki/Torus)). For example, if a termite goes too far to the left, it will wrap around to the right, and instantly appear there. Likewise, if a turtle goes below 0 or above height, then it wraps back around. Thus, we implement an infinite, repeating surface.\n", "\n", "This putting it all together might look like the following. \n", "\n", "Note:\n", "\n", "* termites are represented by ovals. You could make them face the correct direction, or draw legs on them.\n", "* termites turn red when they are carrying a wood chip\n", "* wood chips are represented by red squares" ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " Sketch #86:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #86 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "Termite [] termites; // the array of termites; we'll decide how many later\n", "int[][] gworld; // the 2D world\n", "int RADIUS = 5; // distance that we can sense a wood chip\n", "\n", "class Termite {\n", " int x;\n", " int y;\n", " int vx;\n", " int vy;\n", " int carrying; // zero - not carying chip; 1 - carrying chip\n", " \n", " Termite(int x, int y) {\n", " this.x = int(x);\n", " this.y = int(y);\n", " this.randomizeDirection();\n", " this.carrying = 0;\n", " }\n", " \n", " void draw() {\n", " if (this.carrying == 0) {\n", " fill(0);\n", " } else {\n", " fill(255, 0, 0);\n", " }\n", " ellipse(this.x, this.y, 10, 5);\n", " }\n", " \n", " int get_x(int delta) {\n", " int dx = this.x + delta;\n", " if (dx >= width)\n", " dx -= width;\n", " if (dx < 0)\n", " dx += width;\n", " return dx;\n", " }\n", " \n", " int get_y(int delta) {\n", " int dy = this.y + delta;\n", " if (dy >= height)\n", " dy -= height;\n", " if (dy < 0)\n", " dy += height;\n", " return dy;\n", " }\n", " \n", " void step() {\n", " this.x = this.get_x(this.vx);\n", " this.y = this.get_y(this.vy);\n", " }\n", " \n", " void randomizeDirection() {\n", " this.vx = 0;\n", " this.vy = 0;\n", " while (this.vx == 0 && this.vy == 0) {\n", " this.vx = floor(random(3)) - 1;\n", " this.vy = floor(random(3)) - 1;\n", " }\n", " }\n", " \n", " void pickup_chip(int nx, int ny) {\n", " // Pick it up!\n", " world[nx][ny] = 0;\n", " this.carrying = 1;\n", " }\n", " \n", " void drop_chip(int nx, int ny) {\n", " // Drop it!\n", " world[nx][ny] = 1;\n", " this.carrying = 0;\n", " }\n", "\n", " void move() {\n", " if (random() < .01) { // 1% of the time, change directions\n", " this.randomizeDirection();\n", " }\n", " this.step();\n", " // not carrying a woodchip\n", " if (this.carrying == 0) { // can you smell a chip?\n", " for (int i = -RADIUS; i <= RADIUS; i++) {\n", " if (this.carrying == 0) {\n", " for (int j = -RADIUS; j <= RADIUS; j++) {\n", " nx = this.get_x(i);\n", " ny = this.get_y(j);\n", " if (world[nx][ny] == 1) { // yes!\n", " this.pickup_chip(nx, ny);\n", " break;\n", " }\n", " }\n", " }\n", " }\n", " } else { // carrying a woodchip\n", " // is there a chip nearby?\n", " boolean found = false;\n", " for (int i = -1; i <= 1; i++) { \n", " if (!found) {\n", " for (int j = -1; j <= 1; j++) {\n", " nx = this.get_x(i);\n", " ny = this.get_y(j);\n", " if (world[nx][ny] == 1) { // yes!\n", " // One nearby!\n", " found = true; \n", " break;\n", " }\n", " }\n", " }\n", " }\n", " if (found) {\n", " // now, find an empty spot nearby and drop it! \n", " for (int i = -1; i <= 1; i++) {\n", " if (this.carrying == 1) {\n", " for (int j = -1; j <= 1; j++) {\n", " nx = this.get_x(i);\n", " ny = this.get_y(j);\n", " if (world[nx][ny] == 0) {\n", " // Drop it!\n", " this.drop_chip(nx, ny);\n", " break;\n", " }\n", " }\n", " }\n", " }\n", " }\n", " if (this.carrying == 0) {\n", " // head in opposite direction\n", " this.vx = -this.vx;\n", " this.vy = -this.vy;\n", " // make sure you are far enough away\n", " for (int i = 0; i < RADIUS * 1.5; i++) {\n", " this.step();\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "void setup() {\n", " size(250, 250); // the world\n", " termites = new Termite[10]; // start termites\n", " for (int i =0; i < termites.length; i++) {\n", " termites[i] = new Termite(random(width), random(height));\n", " }\n", " world = new int[width][height]; // match the canvas size\n", " for (int i =0; i < width; i++) {\n", " for (int j =0; j < height; j++) {\n", " world[i][j] = 0;\n", " }\n", " }\n", " for (int i =0; i < 200; i++) { // put some wood chips out:\n", " world[int(random(width))][int(random(height))] = 1;\n", " }\n", "}\n", "\n", "void draw() {\n", " background();\n", " noStroke();\n", " // Move the termites:\n", " for (int i =0; i < termites.length; i++) {\n", " termites[i].move();\n", " termites[i].draw();\n", " } \n", " // Draw them:\n", " for (int i =0; i < width; i++) {\n", " for (int j =0; j < height; j++) {\n", " if (world[i][j] == 1) {\n", " fill(255, 0, 0);\n", " rect(i, j, 3, 3);\n", " }\n", " }\n", " }\n", "}" ] } ], "metadata": { "kernelspec": { "display_name": "Calysto Processing", "language": "processing", "name": "calysto_processing" }, "language_info": { "codemirror_mode": { "name": "text/x-java", "version": 2 }, "file_extension": ".java", "mimetype": "text/x-java", "name": "java" } }, "nbformat": 4, "nbformat_minor": 0 }